#include <gmp.h>
#include <cstdlib>
#include <cstring>
#include <ostream>

using std::ostream;

typedef unsigned short int exp_t; // type of exponents
typedef unsigned char nvars_t; // type of number of variables, can have 255 vars in total
// typedef mpq_t coeff_t; // type of coefficients, might be indirect, hope automatic ctor and dtor
typedef size_t nterms_t; // type of coefficients, might be indirect

//! each term is used with a poly, have: exp_t, mpq_t

class Polynomial {
	public:
			Polynomial(const nvars_t n=1) {nvars = n; nterms = 0; terms = NULL; coeffs = NULL;} // zero poly
			// Polynomial(const nvars_t n, ) {nvars = n; nterms =1; exp_t=NULL; mpq_t=NULL;} // 
			Polynomial(const Polynomial& _poly);
			~Polynomial();
	private:
			nvars_t nvars;
			nterms_t nterms;
			mpq_t* coeffs; // has nterms
			exp_t* terms; // grlex 

			friend ostream& operator << (ostream& os, const Polynomial& in);
};


	ostream& operator << (ostream& os, const Polynomial& in) { 
		if (in.nterms == 0)
				os << 0;
		else  {
				os << in.coeffs[0];
				os << " (";
				for(nvars_t j=1; j <= in.nvars; j++)
						os << in.terms[ 0*in.nvars + j];
				os << ")";
				for (nterms_t i=1; i<in.nterms; i++) {
						os<<" + ";
						os << in.coeffs[i];
						os << " (";
						for(nvars_t j=1; j <= in.nvars; j++)
							os << in.terms[ i*(in.nvars+1) + j];
						os << ")";
				}
			}
		return os;
	}


	Polynomial::~Polynomial() {
	
		if (nterms>0) {
			free(terms);
			for (nterms_t i=0; i< nterms; i++)
					mpq_clear(coeffs[i]);
			free(coeffs);
		}
	}

	Polynomial::Polynomial(const Polynomial& _poly) {
		nterms = _poly.nterms;	
		nvars = _poly.nvars;
		if (nterms>0) {

		size_t t_sz = nterms*(nvars+1)*sizeof(exp_t);
		terms = (exp_t*) malloc(t_sz);
		memcpy (terms,_poly.terms,t_sz);
		t_sz = nterms*sizeof(mpq_t);
		coeffs = (mpq_t*) malloc(t_sz);
		memcpy(coeffs,_poly.coeffs,t_sz);
		for (nterms_t i=0; i< nterms; i++)
				mpq_set(coeffs[i], _poly.coeffs[i]);
		}
	}
